﻿
using Serilog;
using SQLitePCL;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using WatchDog.WatchItemManages;

namespace WatchDog.WinService;

internal class BackgroundJob
{
    //private static System.Timers.Timer _timer;
    private int _err = 0;

    public ILogger Logger { get; private set; }

    public WatchItemManage WatchManage { get; private set; }

    //private readonly ConcurrentStack<long> stack = new();
    //private TimerHandler _task;

    private readonly AsyncTimer _timer = new();
    public BackgroundJob(string strAssemblyDirPath)
    {

        Log.Logger = new LoggerConfiguration()
       //.MinimumLevel.Debug()
       .MinimumLevel.ControlledBy(SerilogHelper.LevelSwitch)
       .WriteTo.Sink(SerilogHelper.Sink)
       .WriteTo.File(strAssemblyDirPath + "/Logs/server-.log",
       rollingInterval: RollingInterval.Day,
       retainedFileTimeLimit: TimeSpan.FromDays(7),
       //outputTemplate: "{HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
       fileSizeLimitBytes: 5242880)
       //.Filter.ByExcluding(e => (int)e.Level < _minimumLogLevel)
       .CreateLogger();

        Logger = Log.Logger;

        WatchManage = new WatchItemManage();

        //int i = 0;
        //_timer = new System.Timers.Timer(1000) { AutoReset = true };
        //_timer.Elapsed += (sender, eventArgs) =>
        //{
        //    i++;
        //    Log.Logger.Information("守护任务发布:{i}", i);
        //    if (stack.IsEmpty)
        //    {
        //        stack.Push(i);
        //    }
        //};


        _timer.Period = 1000; //5 sec.
        _timer.Elapsed = Timer_Elapsed;
        _timer.RunOnStart = false;
    }

    public void Start()
    {
        Log.Logger.Information("正在启动服务...");
        Log.Logger.Debug($"开始 Timer");
        _err = 0;
        _timer.Start();
    }

    public void Stop()
    {
        Log.Logger.Information("正在停止服务...");

        Log.Logger.Debug($"停止 Timer ");
        _timer.Stop();

        //if (_task != null)
        //{
        //    _task.Cancel();
        //}

        DelayedJobManager.Clear();
    }

    public void Restart()
    {
        Stop();

        Log.Logger.Debug($"清理 Config Manage 缓存");
        WatchManage.ClearCache(); // 清除缓存，下次取数据时就会从数据库读取，达到刷新监控项的目的

        _err = 0;

        Start();
    }

    private long taskNo = 0;
    protected virtual async Task Timer_Elapsed(AsyncTimer timer)
    {
        taskNo = 0;

        if (_err > 100)
        {
            Log.Logger.Debug("守护任务执行已连续时出错{_err}次，已跳过", _err);
            await Task.CompletedTask;
        }

        try
        {
            DelayedJobManager.BeforeAddOrUpdate(taskNo);

            var items = WatchManage.GetAllWatchItems();
            if (items.Count > 0)
            {
                try
                {
                    foreach (var item in items)
                    {
                        处理监控项(item);
                    }
                }
                catch (Exception ex)
                {
                    Log.Logger.Error(ex, "执行定时任务时发生错误");
                }
            }
 
            DelayedJobManager.AfterAddOrUpdate();
            _err = 0;
        }
        catch (Exception ex)
        {
            _err += 1;
            if (_err == 1)
            {
                Logger.Error(ex, "守护任务执行时出错");
            }
            else
            {
                Logger.Error("守护任务执行时出错：错误 {_err} 次", _err);
            }
            if (_err >= 100)
            {
                _err = 0;
            }
        }

        static void 处理监控项(WatchItem item)
        {
            if (item.AutoStart == true)
            {
                var runTime = ProcessHelper.GetRunningTotalMinutes(item.FilePath);
                if (runTime > 0)
                {
                    Log.Logger.Debug($"程序{item.FileName},{item.FilePath}正在运行中...");
                    处理定时重启(item, runTime);
                }
                else
                {
                    Log.Logger.Debug($"程序{item.FileName},{item.FilePath}未运行");
                    对未运行的程序进行启动或延时启动(item);
                }
            }

            static void 处理定时重启(WatchItem item, double runTime)
            {
                if (item.ScheduledRestart > 0 && runTime > item.ScheduledRestart)
                {
                    Log.Logger.Debug($"执行定时重启任务：程序{item.FileName}已连续运行{runTime}分钟，重启阀值为{item.ScheduledRestart}分钟。");
                    ProcessHelper.Stop(item.FilePath);
                    ProcessHelper.Start(item.FilePath);
                }
            }

            static void 对未运行的程序进行启动或延时启动(WatchItem item)
            {
                if (item.DelayStart > 0)
                {
                    Log.Logger.Debug($"延迟启动值为：{item.DelayStart} 秒，已加入计划任务");

                    DelayedJobManager.AddOrUpdate(item, async () =>
                    {
                        Log.Logger.Debug($"延迟启动任务：正在完成对程序{item.FileName}的启动（延迟{item.DelayStart}秒）");
                        ProcessHelper.Start(item.FilePath);
                        await Task.CompletedTask;
                    });

                    //DelayedJobManager.AddOrUpdate(item, () =>
                    //{
                    //    Log.Logger.Debug($"延迟启动任务：正在完成对程序{item.FileName}的启动（延迟{item.DelayStart}秒）");
                    //    ProcessHelper.Start(item.FilePath);
                    //});
                    //AddDelayStartTask(item.DelayStart * 1000, item.FilePath);
                }
                else
                {
                    Log.Logger.Debug($"正在启动...");
                    ProcessHelper.Start(item.FilePath);
                }
            }
        }
    }
}

public class TimerHandler
{
    private readonly CancellationTokenSource cts1 = new();
    private readonly CancellationToken token = new();
    public TimerHandler(Func<Task> func)
    {
        token = cts1.Token;

        Task.Run(async () =>
        {
            while (!token.IsCancellationRequested)
            {
                await func();
            }
            IsCompleted = true;
        }, token);
    }

    public void Cancel()
    {
        cts1.Cancel();
    }

    public bool IsCompleted { get; private set; }
}
